package org.common.utils.tableconfig;
import org.common.utils.database.access.DataAccess;
import org.common.utils.field.MethodTable;
import org.common.utils.function.RunnableThrows;
import org.common.utils.tool.ClassTool;
import org.common.utils.tool.StringTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author zhouzhibing
 * @date 2025/5/15
 */
public final class TableConfigData {

    private static final Logger log = LoggerFactory.getLogger(TableConfigManager.class);

    /**
     * 配置表列表<配置表类型，配置表数据对象>
     */
    private final Map<Class<? extends TableData> , TableData> tableMap = new ConcurrentHashMap<>();

    /**
     * 初始化配置表
     * @param packageName 包名
     * @param dataAccess 数据访问对象
     */
    void init(String packageName , DataAccess dataAccess) {
        List<String> tableNameList = dataAccess.select("show tables", (result) -> result.getString(1));
        List<CompletableFuture<?>> futureList = new ArrayList<>(tableNameList.size());

        for (String tableName : tableNameList) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(RunnableThrows.of(() -> {
                try {
                    this.initData(packageName , tableName , dataAccess);
                } catch (Exception e) {
                    throw new RuntimeException("tableName = " + tableName , e);
                }
            }));
            futureList.add(future);
        }

        waitFinish(futureList);
        doTableInit();
    }

    /**
     * 执行配置初始化
     */
    private void doTableInit() {
        List<CompletableFuture<?>> futureList = new ArrayList<>(tableMap.size());
        for (TableData tableData : tableMap.values()) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(RunnableThrows.of(() -> {
                Class<? extends TableData> clzss = tableData.getClass();
                Field firstField = clzss.getSuperclass().getDeclaredFields()[0];
                firstField.setAccessible(true);
                Object firstInstance = firstField.get(tableData);

                //init entity
                if(firstInstance instanceof Map<?,?> firstMap) {
                    Method entityInitMethod = null;
                    for (Object entity : firstMap.values()) {
                        if(entityInitMethod == null) {
                            entityInitMethod = entity.getClass().getDeclaredMethod("init", TableConfigData.class);
                            entityInitMethod.setAccessible(true);
                        }
                        entityInitMethod.invoke(entity , this);
                    }
                } else {
                    Method entityInitMethod = firstInstance.getClass().getDeclaredMethod("init", TableConfigData.class);
                    entityInitMethod.setAccessible(true);
                    entityInitMethod.invoke(firstInstance , this);
                }

                //init data
                Method dataInitMethod = clzss.getDeclaredMethod("init", TableConfigData.class);
                dataInitMethod.setAccessible(true);
                dataInitMethod.invoke(tableData , this);

                log.info("TableConfigManager.doTableInit success dataClass = {} " , tableData.getClass());
            }));
            futureList.add(future);
        }
        waitFinish(futureList);
    }

    /**
     * 初始化数据
     * @param packageName 包名
     * @param tableName 表名
     * @throws Exception 异常
     */
    private void initData(String packageName , String tableName , DataAccess dataAccess) throws Exception {
        String className = StringTool.toMaxHumpString(tableName);
        String currentPackageName = StringTool.toMinString(className);
        packageName = packageName + "." + currentPackageName;
        Class<?> dataClass = null;
        try {
            dataClass = Class.forName(packageName + "." + className + "Data");
        } catch (ClassNotFoundException e) {
            log.warn("TableConfigManager.initData not found class ,  " + packageName + "." + className + "Data");
            return;
        }

        boolean isKv = isKv(dataClass.getSuperclass());

        if (isKv) {
            initKvData(className, packageName , tableName , dataAccess);
        } else {
            initEntityData(className, packageName , tableName , dataAccess);
        }
    }

    /**
     * 初始化kv数据
     * @param className 类型
     * @param packageName 包名
     * @param tableName 表名
     * @param dataAccess 数据访问对象
     * @throws Exception 异常
     */
    private void initKvData(String className, String packageName, String tableName, DataAccess dataAccess) throws Exception {
        //获取父类字段
        Class<?> entityClzss = Class.forName(packageName + "." + className);
        //获取数据列表
        List<KvInfo> kvList = dataAccess.select("select * from " + tableName, null , (result) -> new KvInfo(
            result.getString(1),
            result.getString(2),
            result.getString(3),
            result.getString(4)
        ));

        Object instance = entityClzss.getConstructor().newInstance();
        Field[] fields = entityClzss.getSuperclass().getDeclaredFields();

        for (KvInfo kvInfo : kvList) {
            String key = StringTool.toMinHumpString(kvInfo.key());
            for (Field field : fields) {
                field.setAccessible(true);
                if(field.getName().equals(key)) {
                    Object value = getTypeValue(kvInfo.type() , kvInfo.value());
                    field.set(instance, value);
                    break;
                }
            }
        }

        Class<? extends TableData> dataClass = (Class<? extends TableData>)Class.forName(packageName + "." + className+"Data");
        Field entityInstance = dataClass.getSuperclass().getDeclaredFields()[0];
        entityInstance.setAccessible(true);
        TableData dataTable = dataClass.getConstructor().newInstance();
        entityInstance.set(dataTable , instance);

        tableMap.put(dataClass ,dataTable);
        log.info("TableConfigManager.initKvData success dataClass = {}" , entityClzss.getName());
    }

    /**
     * 初始化实体数据
     * @param className 类型
     * @param packageName 包名
     * @param tableName 表名
     * @param dataAccess 数据访问对象
     * @throws Exception 异常
     */
    private void initEntityData(String className , String packageName , String tableName , DataAccess dataAccess) throws Exception {
        //获取父类字段
        Class<?> entityClzss = Class.forName(packageName + "." + className);
        Field[] fields = entityClzss.getSuperclass().getDeclaredFields();
        Field firstField = fields[0];

        //获取数据列表
        List<Object> list = dataAccess.select("select * from " + tableName, null , (result) -> {
            Object instance = entityClzss.getConstructor().newInstance();
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                field.setAccessible(true);
                Object value = result.getObject(i + 1);
                if(value != null) {
                    field.set(instance, value);
                }
            }
            return instance;
        });

        Map<Object , Object> entityMap = new ConcurrentHashMap<>(list.size());
        for (Object entity : list) {
            Object key = firstField.get(entity);
            entityMap.put(key , entity);
        }

        //只获取父类字段
        Class<? extends TableData> dataClass = (Class<? extends TableData>)Class.forName(packageName + "." + className+"Data");
        Field entityMapField = dataClass.getSuperclass().getDeclaredFields()[0];
        entityMapField.setAccessible(true);
        TableData dataTable = dataClass.getConstructor().newInstance();
        entityMapField.set(dataTable , Collections.unmodifiableMap(entityMap));

        tableMap.put(dataClass , dataTable);
        log.info("TableConfigManager.initEntityData success dataClass = {}" , dataClass.getName());
    }

    /**
     * 判断是否是kv数据
     * @param clzss 类型
     * @return 是否是kv数据
     */
    private boolean isKv(Class<?> clzss) {
        try {
            Method kvMethod = clzss.getDeclaredMethod("get");
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    /**
     * 获取指定配置数据
     * @param clzss 类型
     * @return 返回配置数据对象
     * @param <T> 泛型
     */
    public <T extends TableData> T getData(Class<T> clzss) {
        return (T)tableMap.get(clzss);
    }

    /**
     * 等待列表所有完成
     * @param futureList 执行列表
     */
    private void waitFinish(List<CompletableFuture<?>> futureList) {
        CompletableFuture<Void> allFuture = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]));
        try {
            allFuture.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取类型值
     * @param type 类型
     * @param value 读取值
     * @return 对应类型值
     */
    private Object getTypeValue(String type, String value) {
        if(type == null)
            return value;

        return switch (type) {
            case "int" -> Integer.parseInt(value);
            case "long" -> Long.parseLong(value);
            case "float" -> Float.parseFloat(value);
            case "double" -> Double.parseDouble(value);
            case "boolean", "bool" -> Boolean.parseBoolean(value);
            default -> value;
        };
    }


    /**
     * kv信息
     * @param key 属性名
     * @param value 属性值
     * @param type 属性类型
     * @param desc 描述
     */
    private record KvInfo(String key , String value , String type , String desc) {

    }
}
